package com.mikeli.javacourse.lesson3.homework.gateway.outbound.okhttp;

import com.mikeli.javacourse.lesson3.homework.gateway.handle.RequestHandler;
import com.mikeli.javacourse.lesson3.homework.gateway.outbound.httpclient4.NamedThreadFactory;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.*;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class OkhttpOutboundHandler implements RequestHandler {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    private final ThreadPoolExecutor proxyService;
    private final OkHttpClient okHttpClient;
    private String backendUrl;
    public OkhttpOutboundHandler(String backendUrl) {
        this.backendUrl = backendUrl.endsWith("/")?backendUrl.substring(0,backendUrl.length()-1):backendUrl;
        int cores = Runtime.getRuntime().availableProcessors() * 2;
        long keepAliveTime = 1000;
        int queueSize = 2048;
        RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();//.DiscardPolicy();
        proxyService = new ThreadPoolExecutor(cores, cores,
                keepAliveTime, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(queueSize),
                new NamedThreadFactory("proxyService"), handler);
        okHttpClient = new OkHttpClient();
    }

    @Override
    public void handle(FullHttpRequest fullRequest, ChannelHandlerContext ctx) {
        proxyService.submit(()->doHandle(fullRequest,ctx));
    }

    private void doHandle(FullHttpRequest fullRequest, ChannelHandlerContext ctx) {
        String url = backendUrl + fullRequest.uri();
        fullRequest.headers().entries().forEach((e)->logger.info("当前请求头key={},value={}",e.getKey(),e.getValue()));
        logger.info("请求{}地址",url);
        final Request request = new Request.Builder()
                .url(url)
                .get()//默认就是GET请求，可以不写
                .build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                logger.error("请求{}地址出错",url,e);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                byte[] body = response.body().bytes();
                doResponse(fullRequest,ctx,body);

            }
        });
    }
    private void doResponse(FullHttpRequest fullRequest, ChannelHandlerContext ctx, byte[] body) {
        FullHttpResponse response = null;
        try {
            response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(body));
            response.headers().set("Content-Type", "application/json");
            response.headers().setInt("Content-Length", response.content().readableBytes());
        } catch (Exception e) {
            e.printStackTrace();
            response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NO_CONTENT);
            exceptionCaught(ctx,e);
        } finally {
            if (fullRequest != null) {
                if (!HttpUtil.isKeepAlive(fullRequest)) {
                    ctx.write(response).addListener(ChannelFutureListener.CLOSE);
                } else {
                    response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
                    ctx.write(response);
                }
                ctx.flush();
            }
        }
    }
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }

}
